#include "MTypes.h"
#include "InnerMTypes.h"
#include "MValue.h"
#include "MEnviroment.h"
#include "MException.h"

#include "TestMemory.h"
#include "MTestUtil.h"

#include <vector>
using namespace Marionette;

class TestMEnveriment:public ::testing::Test
{
public:
TestMEnveriment(){
	MAddress::AppendFakeModule("inter.dll",0x00400000);
	XmlTypes = \
"<types>\r\n\
<Array type=\"CHAR\" size=\"16\"/>\r\n\
<struct name=\"TestStruct\">\r\n\
<DWORD name=\"EE\" offset=\"0x0000000C\"/>\r\n\
<DWORD name=\"ID\" offset=\"0x00000000\"/>\r\n\
<CHAR_16 name=\"Name\" offset=\"0x00000028\"/>\r\n\
<DWORD name=\"X\" offset=\"0x00000004\"/>\r\n\
<DWORD name=\"Y\" offset=\"0x00000008\"/>\r\n\
</struct>\r\n\
<struct name=\"TestStruct1\">\r\n\
<DWORD name=\"ID\" offset=\"0x00000000\"/>\r\n\
<DWORD name=\"X\" offset=\"0x00000004\"/>\r\n\
<DWORD_Ptr name=\"X_Ptr\" offset=\"0x0000000C\"/>\r\n\
<DWORD name=\"Y\" offset=\"0x00000008\"/>\r\n\
<TestStruct_Ptr name=\"pStruct\" offset=\"0x0000000C\"/>\r\n\
<TestStruct name=\"vStruct\" offset=\"0x00000010\"/>\r\n\
</struct>\r\n\
<List name=\"TestStruct1List\" valueType=\"TestStruct1\"/>\r\n\
</types>\r\n";
	XmlValues = "\
<values>\r\n\
<MValue name=\"1testValue\" type=\"DWORD\" address=\"0x00000001\"/>\r\n\
<MValue name=\"2testValue2\" type=\"DWORD_Ptr\" module=\"inter.dll\" address=\"0x00000011\"/>\r\n\
</values>\r\n\
";
	XmlListValue = "\
<values>\r\n\
<MValue name=\"3ListValue\" type=\"TestStruct1List_Ptr\" address=\"0x00000011\"/>\r\n\
</values>";
	XmlEnveriment ="<Marionette>\r\n"+  XmlTypes + XmlValues+ "</Marionette>\r\n";
}
~TestMEnveriment(){
	MAddress::ClearFakeModule();
}
public:
	std::string XmlTypes;
	std::string XmlValues;
	std::string XmlListValue;
	std::string XmlEnveriment;
};

TEST_F(TestMEnveriment,NewValue)
{
	MEnviroment env;
	DWORD expectAddr = 0x200;
	env.CreateValue("DWORD","var1",expectAddr);
	MValue v=env.GetValueByName("var1");
	ASSERT_MVALUE_EQ(v,"DWORD",expectAddr);
}
TEST_F(TestMEnveriment,ImportTwoDiffStruct)
{
	MEnviroment MEnv;
	MEnv.ImportFrom(XmlTypes);

	MValue dd = MEnv.NewValue("TestStruct",0x00);
	ASSERT_MVALUE_EQ(dd["ID"],"DWORD",0x00);
	ASSERT_MVALUE_EQ(dd["X"],"DWORD",0x04);
	ASSERT_MVALUE_EQ(dd["Y"],"DWORD",0x08);
	ASSERT_MVALUE_EQ(dd["EE"],"DWORD",0x0c);


	MValue dd1 = MEnv.NewValue("TestStruct1",0x00);
	ASSERT_MVALUE_EQ(dd1["ID"],"DWORD",0x00);
	ASSERT_MVALUE_EQ(dd1["X"],"DWORD",0x04);
	ASSERT_MVALUE_EQ(dd1["Y"],"DWORD",0x08);
	ASSERT_MVALUE_EQ(dd1["X_Ptr"],"DWORD_Ptr",0x0c);
}
TEST_F(TestMEnveriment,ImportSameNameStruct)
{
	MString xmlTypes = \
"<?xml version=\"1.0\"?>\n\
<types>\n\
<struct name=\"SameNameStruct\">\n\
</struct>\n\
<struct name=\"SameNameStruct\">\n\
</struct>\n\
</types>";
	MEnviroment MEnv;
	ASSERT_THROW(MEnv.ImportFrom(xmlTypes),TypeNameAlreadyExist);
}
TEST_F(TestMEnveriment,ImportValues)
{

	MEnviroment env;
	env.ImportFrom(XmlValues);

	ASSERT_MVALUE_EQ(env.GetValueByName("1testValue"),"DWORD",0x01);
	ASSERT_MVALUE_EQ(env.GetValueByName("2testValue2"),"DWORD_Ptr",0x00400011);
}
TEST_F(TestMEnveriment,ExportToXml)
{
	MEnviroment env;
	env.ImportFrom(XmlEnveriment);
	MString targetXml;
	env.ExportTo(targetXml);
	ASSERT_EQ(XmlEnveriment,targetXml);
}
TEST_F(TestMEnveriment,AccessMValueByPathString)
{
	MEnviroment env;
	env.ImportFrom(XmlEnveriment);
	env.CreateValue("TestStruct1","MyValue",0x0000);
	
	ASSERT_NO_THROW(env.GetValueByName("MyValue.vStruct.Name"));
	MValue v = env.GetValueByName("MyValue.vStruct.Name");
	ASSERT_MVALUE_EQ(v,"CHAR_16",0x0000038);
}